<?php

namespace app\api\controller;

use think\Controller;
use think\Request;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\ValidationData;
use Lcobucci\JWT\Parser;
use \think\Exception;

abstract class Api extends Controller
{ 
    private $key      = 'b456b465f7';
    protected $result = ['code' => 200, 'data' => ''];
    protected $token  = '';
    protected $model  = [];

    protected $beforeActionList = [
        'checkToken',
        'checkSign'
    ];

    protected static $loginuser = '';

    public function _initialize()
    {
                
    }
    protected function checkToken()
    {
        $token = $this->request->header('token');
        
        if ($token) {
            $data = new ValidationData();
            $data->setIssuer('https://api.shsytour.cn');
            $data->setAudience('https://api.shsytour.cn');
            $data->setId($this->key);
            //$data->setCurrentTime(time() + 3000);
            
            $token = (new Parser())->parse((string) $token);

            if ($token->validate($data)) {
                $this->token = $this->request->header('token');
            }else{
                throw new Exception('check token fail', 800);
            }
        }else{
            throw new Exception('token is empty', 801);  
        }
    }
    /**
     * 校验sign
     * @return [type] [description]
     */
    protected function checkSign($data = null)
    {
        $data = $data ? : $this->request->param();
        $sign = $this->request->header('sign');
        if ($sign && $sign === $this->mixSign($data)) {
            return true;
        }
        throw new Exception('check sign fail:' . $this->mixSign($data), 700);
    }
    /**
     * 组合sign
     * @param  [type] $data [description]
     * @return [type]       [description]
     */
    protected function mixSign($data)
    {
        $str  = '';
        $data = array_diff_key($data, array_flip(['_url', 'sign', 's', '_token', 'action', 'page']));
        ksort($data);
        
        foreach ($data as $k => $value) {
            if (!is_array($value)) {
                $value = urldecode($value);
                if ($value || $value === '0') {
                    $str .= $k . $value;
                }
            }
        }

        $str .= 'key' . $this->key;
        return md5($str);
    }
    public function checkRight()
    {
        if (!$this->token) {
            throw new Exception('check token fail', 800);
        }
    }
    public function getTokenUserInfo($field = '')
    {
        try {
            $this->checkRight();
            $token = (new Parser())->parse((string) $this->token);
            $user  = json_decode($token->getClaim('user_info'));
            if (empty(self::$loginuser) || self::$loginuser['id'] != $user->id) {
                self::$loginuser = model('Users')->get($user->id);
            }
            if (!self::$loginuser) {
                throw new Exception('用户不存在', 800);
            }
            if ($field) {
                if (isset(self::$loginuser[$field])) {
                    return self::$loginuser[$field]; 
                }
                throw new Exception('用户属性不存在', 800);
            }
            return self::$loginuser;
            
        } catch (\Exception $e) {
            throw new Exception($e->getMessage(), $e->getCode());
        }
          
    }
    /**
     * 
     *
     * @return \think\Response
     */
    protected function createToken($user)
    {
        $token = (new Builder())->issuedBy('https://api.shsytour.cn')
                                ->canOnlyBeUsedBy('https://api.shsytour.cn')
                                ->identifiedBy($this->key, true)
                                //->expiresAt(time() + 3600)
                                ->with('user_info', $user)
                                ->getToken();

        return $token->__toString();
    }
    public function setLocale()
    {
        return $this->getToken(model('Users')->login('18633846582', 'xiaoxiao')->visible(['id','mobile'])->toJson());
    }
    protected function setCode($code)
    {
        $this->result['code'] = $code;
    }
    protected function setData($data)
    {
        $this->result['data'] = $data;
    }
    protected function send($data = null, $code = null)
    {
        $code && $this->setCode($code);
        $data && $this->setData($data);
        return $this->result;
    }
}
